fix: increase Hyperlight I/O buffer for large hostfs writes - #81
Conversation
The Hyperlight SDK defaults input/output shared-memory stacks to 16 KiB each. The hostfs VFS layer chunks writes at 32 KiB, but after base64 encoding + JSON envelope + FlatBuffer framing, a single chunk occupies ~44 KiB — overflowing the 16 KiB output stack and causing hcall_push to fail with EIO on writes exceeding ~12 KiB. Set the I/O buffer size to 128 KiB (sufficient for any single-chunk RPC with headroom) and expose it as a configurable field on VmConfig and SandboxBuilder so embedders can tune it for their workload. Signed-off-by: danbugs <danilochiarlone@gmail.com>
There was a problem hiding this comment.
Pull request overview
This PR increases the default Hyperlight shared-memory I/O buffer sizes to prevent host function call payload overflows during large hostfs write RPCs, and exposes a knob so embedders can tune the buffer size.
Changes:
- Add
io_buffer_sizetoVmConfigand plumb it through to HyperlightSandboxConfigurationinput/output data sizes. - Add
SandboxBuilder::io_buffer_size(...)for configuring the shared-memory I/O buffers. - Add an integration test that writes a >32 KiB binary file via hostfs and verifies its contents on the host.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| host/tests/pyhl_runtime.rs | Adds a runtime integration test covering large binary writes through hostfs. |
| host/src/lib.rs | Introduces configurable I/O buffer sizing and increases the default to 128 KiB. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| pub struct VmConfig { | ||
| pub heap_size: u64, | ||
| pub stack_size: u64, | ||
| pub io_buffer_size: usize, | ||
| } |
There was a problem hiding this comment.
Fixed — added #[non_exhaustive] to VmConfig.
| fn sandbox_config(&self) -> SandboxConfiguration { | ||
| let mut cfg = SandboxConfiguration::default(); | ||
| cfg.set_heap_size(self.heap_size); | ||
| cfg.set_input_data_size(self.io_buffer_size); | ||
| cfg.set_output_data_size(self.io_buffer_size); |
There was a problem hiding this comment.
Pre-existing issue — stack_size predates this PR. Tracked separately.
| let timing = rt | ||
| .run_code("with open('/host/big.bin', 'wb') as f: f.write(b'x' * 40000)") | ||
| .unwrap(); | ||
| assert_eq!(timing.exit_code, 0); | ||
|
|
||
| let data = std::fs::read(tmp.join("big.bin")).unwrap(); | ||
| assert_eq!(data.len(), 40000); | ||
| assert!(data.iter().all(|&b| b == b'x')); |
There was a problem hiding this comment.
Fixed — using 40 * 1024 now.
- Mark VmConfig as #[non_exhaustive] to prevent semver breakage when new fields are added - Use explicit 40 KiB (40 * 1024) in the large binary write test to match the PR description and make the boundary condition clearer Signed-off-by: danbugs <danilochiarlone@gmail.com>
Signed-off-by: danbugs <danilochiarlone@gmail.com>
There was a problem hiding this comment.
Linux Benchmarks
Details
| Benchmark suite | Current: dab60b0 | Previous: 20ccc2d | Ratio |
|---|---|---|---|
hello_world (median) |
20 ms |
20 ms |
1 |
pandas (median) |
110 ms |
110 ms |
1 |
density (per VM) |
7 MB |
7 MB |
1 |
snapshot (disk) |
385 MiB |
385 MiB |
1 |
This comment was automatically generated by workflow using github-action-benchmark.
There was a problem hiding this comment.
Windows Benchmarks
Details
| Benchmark suite | Current: dab60b0 | Previous: 20ccc2d | Ratio |
|---|---|---|---|
hello_world (median) |
267 ms |
261 ms |
1.02 |
pandas (median) |
896 ms |
800 ms |
1.12 |
density (per VM) |
6 MB |
6 MB |
1 |
snapshot (disk) |
392 MiB |
392 MiB |
1 |
This comment was automatically generated by workflow using github-action-benchmark.
Summary
io_buffer_sizeonVmConfigandSandboxBuilderso embedders can tune itruntime_filesystem_large_binary_writeintegration test (40 KiB binary blob)Test plan
runtime_filesystem_large_binary_writepassescargo checkclean